﻿using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Text;

namespace ZOVNP.Engine
{
    /// <summary> Настройщик соединения с базой данных. </summary>
    /// <remarks> Является построителем объекта соединения с базой данных. Используется только в отладочной версии приложения. </remarks>
    public class ConnectionTuner
    {
        #region Поля

        private static ConnectionTuner instance;

        #endregion

        #region Свойства

        /// <summary> Получить инстанцию настройщика, специфичного для текущих условий работы. </summary>
        /// <remarks> Настройщики назначаются в зависимости от имени рабочей станции. </remarks>
        public static ConnectionTuner Instance
        {
            get
            {
                if (instance != null) return instance;
                switch (System.Environment.MachineName.ToUpperInvariant())
                {
                    case "MAXIMOV":
                        //instance = new EFProfilerConnectionTuner();
                        //instance = new SqlConnectionTuner();
                        instance = new ConnectionTuner();
                        break;
                    default:
                        instance = new ConnectionTuner();
                        break;
                }
                return instance;
            }
        }

        #endregion

        #region Методы

        /// <summary> Инициализировать настройщик соединения. </summary>
        public virtual void Initialize() { }

        /// <summary> Создать и настроить соединение с источником данных. </summary>
        /// <param name="ConnectionString"> Строка соединения с источником данных. </param>
        /// <param name="DefaultCreator"> Делегат для создания соединения по умолчанию. </param>
        /// <returns> Настроенное соединение с источником данных. </returns>
        public virtual DbConnection TuneConnection(string ConnectionString, Func<string, DbConnection> DefaultCreator) { return DefaultCreator(ConnectionString); }

        #endregion
    }

    internal class SqlConnectionTuner : ConnectionTuner
    {
        public override DbConnection TuneConnection(string ConnectionString, Func<string, DbConnection> DefaultCreator)
        {
            var result = base.TuneConnection(ConnectionString, DefaultCreator);
            if (result is System.Data.SqlClient.SqlConnection)
                return new Fintech.Utils.Database.ProfiledSqlConnection((System.Data.SqlClient.SqlConnection)result);
            return result;
        }
    }

    /// <summary> Класс настройщика, использующего Entity Framework Profiler. </summary>
    internal class EFProfilerConnectionTuner : ConnectionTuner
    {
        #region Поля

        private static string filename1 = "D:\\EntityFramework.Profiler-Build-831\\HibernatingRhinos.Profiler.Appender.dll";
        private static string filename2 = "D:\\EntityFramework.Profiler-Build-831\\MyProfiledConnection.dll";

        #endregion

        #region Методы

        /// <summary> Инициализировать настройщик соединения. </summary>
        /// <remarks>
        /// Подключение профилировщика для платформы Entity Framework. Явно ссылка не ставится, чтобы не нарушать работу проекта на других машинах.
        /// Чтобы заработал профилировщик нужно вызвать статический метод Initialize класса EntityFrameworkProfiler.
        /// </remarks>
        public override void Initialize()
        {
            base.Initialize();
            if (System.IO.File.Exists(filename1))
            {
                var asm = System.Reflection.Assembly.LoadFrom(filename1);
                var type = asm.GetType("HibernatingRhinos.Profiler.Appender.EntityFramework.EntityFrameworkProfiler");
                type.GetMethod("Initialize", System.Type.EmptyTypes).Invoke(null, null);
            }
        }

        /// <summary> Создать профилируемое соединение с источником данных. </summary>
        /// <param name="ConnectionString"> Строка соединения с источником данных. </param>
        /// <param name="DefaultCreator"> Делегат для создания непрофилируемого соединения по умолчанию. </param>
        /// <returns> Профилируемое соединение с источником данных. </returns>
        public override DbConnection TuneConnection(string ConnectionString, Func<string, DbConnection> DefaultCreator)
        {
            var result = base.TuneConnection(ConnectionString, DefaultCreator);
            var asm = System.Reflection.Assembly.LoadFrom(filename2);
            return asm.GetType("MyProfiledConnection").GetConstructors()[0].Invoke(new object[] { result }) as DbConnection;
        }

        #endregion
    }
}
